package com.easily.factory.aop;

import com.easily.label.*;
import com.easily.system.dict.ObjectMethods;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AopObject {
    private String[] aopValue;
    // aop切入方法所在的类
    private final Object aopObject;

    // aop切入方法
    private Method beforeMethod;
    private Method afterMethod;
    private Method exceptionMethod;
    private Method finallyMethod;

    public AopObject(Object aopObject){
        this.aopObject = aopObject;
        if(aopObject==null) return;
        for (Method aopMethod : aopObject.getClass().getMethods()) {
            if(aopMethod.isAnnotationPresent(AopBefore.class)){
                this.beforeMethod = aopMethod;
            }else if(aopMethod.isAnnotationPresent(AopAfter.class)){
                this.afterMethod = aopMethod;
            }else if(aopMethod.isAnnotationPresent(AopException.class)){
                this.exceptionMethod = aopMethod;
            }else if(aopMethod.isAnnotationPresent(AopFinally.class)) {
                this.finallyMethod = aopMethod;
            }
        }

        aopValue = aopObject.getClass().getAnnotation(Aop.class).value();
    }

    // 判断这个类需不需要aop代理

    public boolean isAopClass(String className){
        for (String value:aopValue){
            Pattern pattern = Pattern.compile(value);
            Matcher matcher = pattern.matcher(className);
            if (matcher.matches()) return true;
        }
        return false;
    }

    // 判断是不是这个类的所有方法都需要代理
    public boolean isAllMethod(String className){
        return false;
    }

    // 判断某个方法是否需要代理
    public boolean isAopMethod(String methodName){

            for (String value : aopValue) {
                Pattern pattern = Pattern.compile(value);
                Matcher matcher = pattern.matcher(methodName);
                if (matcher.matches()) return true;
            }

        return false;
    }

    /**
     * 执行切面
     */
    public void sectionInvoke(MethodBody methodBody,Method aopMethod) throws InvocationTargetException, IllegalAccessException {
        if (aopMethod == null) return;

        // 判断method有哪些参数
        List<Object> list = new ArrayList<>();

        for (Class<?> parameterType : aopMethod.getParameterTypes()) {
            if(parameterType == Object.class){
                // 传递目标方法所在的类
                list.add(methodBody.getObject());
            }else if(parameterType == Method.class){
                // 传递目标方法
                list.add(methodBody.getMethod());
            }else if(parameterType == Object[].class){
                // 传递目标方法的参数
                list.add(methodBody.getArgs());
            }else if(parameterType == MethodBody.class){
                // MethodBody中包含了目标方法的所有信息
                list.add(methodBody);
            }else {
                list.add(null);
            }
        }

        // list转数组
        Object[] args = list.toArray();
        aopMethod.invoke(aopObject, args);
    }

    public void advice(MethodBody methodBody) throws InvocationTargetException, IllegalAccessException {
        sectionInvoke(methodBody,beforeMethod);
    }
    public void afterAdvice(MethodBody methodBody) throws InvocationTargetException, IllegalAccessException {
        sectionInvoke(methodBody,afterMethod);
    }
    public void exceptionAdvice(MethodBody methodBody,Throwable e) throws Throwable {
        if (methodBody == null) {
            throw e;
        }else {
            methodBody.setException(e);
            sectionInvoke(methodBody,exceptionMethod);
        }
    }
    public void finallyAdvice(MethodBody methodBody) throws InvocationTargetException, IllegalAccessException {
        sectionInvoke(methodBody,finallyMethod);
    }
}
